﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;

namespace VerificationCode
{
    public static class Sample
    {
        private const int PixelDiffThreshold = 25;

        private const int HHistDiffThreshold = 3000;

        private const int VHistDiffThreshold = 3000;

        private static List<double> HHist = new List<double>();

        private static List<double> VHist = new List<double>();

        public static void Create(Bitmap bmp, string label)
        {
            string s = label;
            string map = "";
            string HHstr = "";
            string VHstr = "";
            Feature(bmp, out map, out HHstr, out VHstr);

            s = s + "!" + map + "@" + HHstr + "#" + VHstr;

            StreamWriter m_WriteFile = new StreamWriter(@"Sample.txt", true);
            m_WriteFile.WriteLine(s);
            m_WriteFile.Flush();
            m_WriteFile.Close();
        }

        public static string Classify(Bitmap bmp)
        {
            string map = "";
            string HHstr = "";
            string VHstr = "";
            Feature(bmp, out map, out HHstr, out VHstr);

            List<string> label = new List<string>();
            List<int> num = new List<int>();
            string rLine = "";
            StreamReader m_ReadFile = File.OpenText(@"Sample.txt");
            int index = 0;
            while((rLine = m_ReadFile.ReadLine()) != null )
            {
                if (IsSimilar(map, rLine))
                {
                    for (int i = 0; i < rLine.Length; i++)
                    {
                        if(rLine[i] == '!')
                        {
                            index = i;
                            break;
                        }
                    }
                    string name = rLine.Substring(0, index);
                    index = 0;
                    if (!IsIn(name, label, out index))
                    {
                        label.Add(name);
                        num.Add(1);
                    }
                    else
                    {
                        num[index]++;
                    }
                }//if
            }//while
            m_ReadFile.Close();

            index = 0;
            int temp = 0;
            for (int i = 0; i < num.Count; i++)
            {
                if (temp < num[i])
                {
                    temp = num[i];
                    index = i;
                }
            }
            if (label.Count == 0)
                return "";
            return label[index];
        }

        private static bool IsIn(string name, List<string> label, out int index)
        {
            for (int i = 0; i < label.Count; i++)
            {
                if (label[i] == name)
                {
                    index = i;
                    return true;
                }
            }
            index = -1;
            return false;
        }

        private static bool IsSimilar(string map, string record)
        {
            int indexMap = 0;
            int indexHHist = 0;
            int indexVHist = 0;
            for (int i = 0; i < record.Length; i++)
            {
                switch (record[i])
                {
                    case '!':
                        indexMap = i;
                        break;
                    case '@':
                        indexHHist = i;
                        break;
                    case '#':
                        indexVHist = i;
                        break;
                }
            }

            int mapDiffCount = 0;
            double hHistDiffCount = 1;
            double vHistDiffCount = 1;
            for (int i = indexMap + 1; i < indexHHist; i++)
            {
                if (map[i - indexMap - 1] != record[i])
                {
                    mapDiffCount++;
                }
            }
            List<double> recordH = ConvertRecord(record.Substring(indexHHist + 1,indexVHist - indexHHist - 1));
            List<double> recordV = ConvertRecord(record.Substring(indexVHist + 1, record.Length - indexVHist - 1));
            for (int i = 0; i < recordH.Count; i++)
            {
                hHistDiffCount *= Distance(HHist[i], recordH[i]);
            }
            for (int i = 0; i < recordV.Count; i++)
            {
                vHistDiffCount *= Distance(VHist[i], recordV[i]);
            }

            bool b1 = (mapDiffCount < PixelDiffThreshold) &&  (hHistDiffCount < HHistDiffThreshold) && (vHistDiffCount > VHistDiffThreshold);
            bool b2 = (mapDiffCount < PixelDiffThreshold) &&  (hHistDiffCount > HHistDiffThreshold) && (vHistDiffCount < VHistDiffThreshold);
            bool b3 = (mapDiffCount > PixelDiffThreshold) &&  (hHistDiffCount < HHistDiffThreshold) && (vHistDiffCount < VHistDiffThreshold);
            bool b4 = (mapDiffCount < PixelDiffThreshold) &&  (hHistDiffCount < HHistDiffThreshold) && (vHistDiffCount < VHistDiffThreshold);

            if (b1 || b2 || b3 || b4)
            {
                return true;
            }
            else
                return false;
        }

        private static List<double> ConvertRecord(string record)
        {
            List<double> result = new List<double>();
            string value = "";
            for (int i = 0; i < record.Length; i++)
            {
                if (record[i] == '&')
                {
                    value = record.Substring(0, i);
                    result.Add(double.Parse(value));
                    record = record.Substring(i + 1, record.Length - i - 1);
                    i = 0;
                }
            }
            result.Add(double.Parse(record));
            return result;
        }

        private static int Distance(double d1, double d2)
        {
            double d = System.Math.Abs(d1 - d2);
            if (d > 0.5)
                return 50;
            else if (d > 0.4)
                return 25;
            else if (d > 0.3)
                return 10;
            else if (d > 0.2)
                return 5;
            else
                return 1;
        }

        private static void Feature(Bitmap bmp, out string mstr, out string HHstr, out string VHstr)
        {
            HHist = new List<double>();
            VHist = new List<double>();
            int count = 0;
            mstr = "";
            for (int j = 0; j < bmp.Height; j++)
            {
                count = 0;
                for (int i = 0; i < bmp.Width; i++)
                {
                    if (Diff(bmp.GetPixel(i, j), Color.White) < 10)
                        mstr = mstr + "0";
                    else
                    {
                        mstr = mstr + "1";
                        count++;
                    }
                }//for i
                HHist.Add(count);
            }//for j
            for (int i = 0; i < bmp.Width; i++)
            {
                count = 0;
                for (int j = 0; j < bmp.Height; j++)
                {
                    if (Diff(bmp.GetPixel(i, j), Color.Black) < 10)
                        count++;
                }
                VHist.Add(count);
            }

            //处理HHist与VHist中的数据
            double Max = 0;
            HHstr = "";
            VHstr = "";
            for (int i = 0; i < HHist.Count; i++)
            {
                Max = Math.Max(Max, HHist[i]);
            }
            for (int i = 0; i < HHist.Count; i++)
            {
                HHist[i] = HHist[i] / Max;
                HHstr = HHstr + Math.Round(HHist[i], 4) + "&";
            }
            HHstr = HHstr.Substring(0, HHstr.Length - 1);
            Max = 0;
            for (int i = 0; i < VHist.Count; i++)
            {
                Max = Math.Max(Max, VHist[i]);
            }
            for (int i = 0; i < VHist.Count; i++)
            {
                VHist[i] = VHist[i] / Max;
                VHstr = VHstr + Math.Round(VHist[i], 4) + "&";
            }
            VHstr = VHstr.Substring(0, VHstr.Length - 1);
        }

        private static int Diff(Color c1, Color c2)
        {
            int R = System.Math.Abs(c1.R - c2.R);
            int G = System.Math.Abs(c1.G - c2.G);
            int B = System.Math.Abs(c1.B - c2.B);
            return B + G + R;
        }

        public static Bitmap DrawHist(Bitmap bmp)
        {
            Color pic = Color.Red;
            Color axis = Color.Black;
            Bitmap result = new Bitmap(bmp.Width * 2, bmp.Height * 2);
            Graphics g = Graphics.FromImage(result);
            g.Clear(Color.White);

            for (int i = 0; i < bmp.Height; i++)
            {
                result.SetPixel(0, i, axis);
                result.SetPixel(bmp.Width, bmp.Height + i, axis);
            }

            for (int i = 0; i < bmp.Width; i++)
            {
                result.SetPixel(i, bmp.Height - 1, axis);
                result.SetPixel(bmp.Width + i, result.Height - 1, axis);
            }

            result.SetPixel(1, 1, axis);
            result.SetPixel(bmp.Width - 2, bmp.Height - 2, axis);
            result.SetPixel(bmp.Width, bmp.Height, Color.White);
            result.SetPixel(bmp.Width, bmp.Height + 1, Color.White);
            result.SetPixel(bmp.Width + 1, bmp.Height + 3, axis);
            result.SetPixel(result.Width - 2, result.Height - 2, axis);

            

            int count = 0;
            for (int j = 0; j < bmp.Height; j++)
            {
                count = 0;
                for (int i = 0; i < bmp.Width; i++)
                {
                    if (Diff(bmp.GetPixel(i,j),Color.Black) < 10)
                    {
                        result.SetPixel(bmp.Width + i, j, Color.Black);
                        count++;
                    }
                }
                for (int k = 0; k < count; k++)
                {
                    result.SetPixel(k + 1,j,pic);
                }
            }

            for (int i = 0; i < bmp.Width; i++)
            {
                count = 0;
                for (int j = 0; j < bmp.Height; j++)
                {
                    if (Diff(bmp.GetPixel(i, j), Color.Black) < 10)
                        count++;
                }
                for (int k = 0; k < count; k++)
                {
                    result.SetPixel(bmp.Width + i, result.Height - 2 - k, pic);
                }
            }
            return result;
        }


    }

    public class OCR
    {
        private const int CountThreshold = 40;

        private const int ColorDiffThreshold = 120;

        private int[,] label;

        private int searchCount = 0;

        public Bitmap Derived(Bitmap bmp)
        {
            Bitmap result = new Bitmap(bmp);
            Graphics g = Graphics.FromImage(result);
            g.Clear(Color.White);

            List<int> Characters = new List<int>();
            label = new int[bmp.Width, bmp.Height];
            Color selectedColor = Color.White;
            int index = 0;

            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    selectedColor = bmp.GetPixel(i, j);
                    if (Diff(selectedColor, Color.White) < 10)
                    {
                        continue;
                    }
                    index++;
                    searchCount = 0;
                    label = new int[bmp.Width, bmp.Height];
                    FindCharacter(selectedColor, i, j, bmp, label, index, 0);
                    if ((searchCount > CountThreshold) && (searchCount < 400))
                    {
                        DrawBmp(result, bmp, index);
                    }
                }//for j
            }//for i
            return result;
        }

        public List<Bitmap> Segment(Bitmap bmp)
        {
            List<Bitmap> list = new List<Bitmap>();
            for (int i = 0; i < 4; i++)
            {
                Bitmap b = new Bitmap(bmp.Width / 4, bmp.Height);
                for (int j = i * (bmp.Width / 4); j < (i + 1) * (bmp.Width / 4); j++)
                {
                    for (int k = 0; k < bmp.Height; k++)
                    {
                        b.SetPixel(j % (bmp.Width / 4), k, bmp.GetPixel(j, k));
                    }
                }
                list.Add(b);
            }
            return list;
        }

        private int Diff(Color c1, Color c2)
        {
            int R = System.Math.Abs(c1.R - c2.R);
            int G = System.Math.Abs(c1.G - c2.G);
            int B = System.Math.Abs(c1.B - c2.B);
            return B + G + R;
        }

        private void FindCharacter(Color c, int x, int y, Bitmap bTemp, int[,] label, int index, int count)
        {
            if (x < 0 || y < 0 || x >= bTemp.Width || y >= bTemp.Height)
            {
                return;
            }
            if (label[x, y] > 0)
            {
                return;
            }
            if (Diff(c, Color.White) < 10)
            {
                return;
            }
            searchCount = Math.Max(searchCount, count);
            Color cTemp = bTemp.GetPixel(x, y);
            if (Diff(cTemp, c) < ColorDiffThreshold)
            {
                label[x, y] = index;
                count++;
                FindCharacter(cTemp, x - 1, y, bTemp, label, index, count);
                FindCharacter(cTemp, x, y - 1, bTemp, label, index, count);
                FindCharacter(cTemp, x + 1, y, bTemp, label, index, count);
                FindCharacter(cTemp, x, y + 1, bTemp, label, index, count);

                FindCharacter(cTemp, x - 1, y - 1, bTemp, label, index, count);
                FindCharacter(cTemp, x + 1, y - 1, bTemp, label, index, count);
                FindCharacter(cTemp, x - 1, y + 1, bTemp, label, index, count);
                FindCharacter(cTemp, x + 1, y + 1, bTemp, label, index, count);

                FindCharacter(cTemp, x - 2, y, bTemp, label, index, count);
                FindCharacter(cTemp, x, y - 2, bTemp, label, index, count);
                FindCharacter(cTemp, x + 2, y, bTemp, label, index, count);
                FindCharacter(cTemp, x, y + 2, bTemp, label, index, count);

            }
            else if (Diff(cTemp, c) < ColorDiffThreshold * 1.5)
            {
                label[x, y] = index;
            }
        }

        private void DrawBmp(Bitmap result, Bitmap source, int index)
        {
            for (int i = 0; i < result.Width; i++)
            {
                for (int j = 0; j < result.Height; j++)
                {
                    if (label[i, j] == index)
                        //result.SetPixel(i, j, source.GetPixel(i,j));
                        result.SetPixel(i, j, Color.Black);
                }
            }
        }


    }
}
